package cn.net.cfss.fgbp.provider.console.biz;

import cn.hutool.core.date.DateUtil;
import cn.hutool.crypto.digest.BCrypt;
import cn.net.cfss.fgbp.api.console.constant.*;
import cn.net.cfss.fgbp.api.console.dto.*;
import cn.net.cfss.fgbp.api.console.inte.ISysUserLoginLogService;
import cn.net.cfss.fgbp.api.console.util.HttpClientUtil;
import cn.net.cfss.fgbp.api.console.vo.SysMenuVo;
import cn.net.cfss.fgbp.api.console.vo.SysUserDetailVo;
import cn.net.cfss.fgbp.api.console.vo.SysUserLoginVo;
import cn.net.cfss.fgbp.api.console.vo.SysUserVo;
import cn.net.cfss.fgbp.base.common.biz.BaseBiz;
import cn.net.cfss.fgbp.base.constant.ErrCodeEnum;
import cn.net.cfss.fgbp.base.except.CodeException;
import cn.net.cfss.fgbp.provider.console.dao.SysUserDtoMapper;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.entity.ContentType;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

@Slf4j
@Service
public class SysUserDtoBiz extends BaseBiz<SysUserDtoMapper, SysUserDto> {

    @Autowired
    ISysUserLoginLogService sysUserLoginLogService;


    @Autowired
    SysUserRoleDtoBiz sysUserRoleDtoBiz;

    @Autowired
    SysMenuDtoBiz sysMenuDtoBiz;

    @Autowired
    SysRoleProjectDtoBiz sysRoleProjectDtoBiz;

    @Autowired
    SysRoleDtoBiz sysRoleDtoBiz;

    @Value("${application.resource.servProAdmin:}")
    private String resourceServProAdmin;

    @Value("${application.resource.superAdmin:}")
    private String resourceSuperAdmin;

    @Value("${crm.getProject:}")
    private String crmGetProject;



    /**
     * 批量逻辑删除
     *
     * @param userIds
     * @return
     */
    public int deleteBatchByLogic(List<Long> userIds) {
        return mapper.deleteBatchByLogic(userIds);
    }

    /**
     * 根据条件查询列表
     *
     * @param sysUserVo
     * @return
     */
    public List<SysUserVo> queryList(SysUserVo sysUserVo) {
        return mapper.queryList(sysUserVo);
    }

    /**
     * 根据用户ID查询
     *
     * @param userId
     * @return
     */
    public SysUserVo getByUserId(Long userId) {
        return mapper.getByUserId(userId);
    }


    public boolean check(String username, Long id) {
        if (id != null) {
            SysUserDto dto = new SysUserDto();
            dto.setId(id);
            dto.setDeleteFlag(DeleteFlagEnum.NOT_DEL);
            dto = selectOne(dto);
            //SysUserDto dto = selectById(id);
            if (username.equals(dto.getUsername())) {
                return true;
            }
        }

        if (mapper.check(username) > 0) {
            return false;
        }
        return true;
    }

    /**
     * 用户登录
     *
     * @param username
     * @param password
     * @return
     */
    public SysUserLoginVo login(String username, String password, String ip) {
        List<Long> roles = new ArrayList<>();
        if (StringUtils.isBlank(username) || StringUtils.isBlank(password)) {
            return null;
        }
        username = username.trim();
        password = password.trim();

        SysUserDto user = new SysUserDto();
        user.setUsername(username);
        user.setDeleteFlag(DeleteFlagEnum.NOT_DEL);

        user = selectOne(user);

        //记录登录日志
        SysUserLoginLogDto loginLog = new SysUserLoginLogDto();
        loginLog.setLoginName(username);
        loginLog.setLoginType(LoginTypeEnum.LOG_IN);
        loginLog.setLoginMode(LoginModeEnum.USERNAME_PASSWORD);

        //TODO 抛出用户名错误
        if (null == user) {
            loginLog.setLoginResult(LoginResultEnum.LOGIN_FAIL);
            loginLog.setException("用户名错误");
            loginLog.setLoginIp(ip);
            sysUserLoginLogService.saveLog(loginLog);
            log.info("用户名错误:{}", username);
            throw new CodeException(ErrCodeEnum.ERR_CONSOLE, "用户名错误");
        }
        //TODO 抛出用户状态异常错误
        if (UserStatusEnum.NORMAL != user.getUserStatus()) {
            //判断最近登录时间是否是今天，状态是否是已锁定,如果最近登录时间与当前时间不是同一天，系统自动解锁
            if (UserStatusEnum.LOCKED == user.getUserStatus() && !this.isToday(new Date(), user.getLastLoginSuccTime())) {
                user.setUserStatus(UserStatusEnum.NORMAL);
            } else {
                loginLog.setLoginResult(LoginResultEnum.LOGIN_FAIL);
                loginLog.setException("用户" + user.getUserStatus().getDisplayName());
                loginLog.setLoginIp(ip);
                sysUserLoginLogService.saveLog(loginLog);
                log.info("用户名{}状态异常:{}", username, user.getUserStatus().getDisplayName());
                throw new CodeException(ErrCodeEnum.ERR_CONSOLE, "用户" + user.getUserStatus().getDisplayName());
            }
        }
        //TODO 抛出用户Salt为null错误
        if (StringUtils.isBlank(user.getSalt())) {
            loginLog.setLoginResult(LoginResultEnum.LOGIN_FAIL);
            loginLog.setException("用户Salt为null");
            loginLog.setLoginIp(ip);
            sysUserLoginLogService.saveLog(loginLog);
            log.info("用户名{}Salt为null");
            throw new CodeException(ErrCodeEnum.ERR_CONSOLE, "用户信息错误");
        }
        //加密后的密码
        String encPassword = BCrypt.hashpw(password, user.getSalt());
        //TODO 抛出用户密码错误
        if (!encPassword.equals(user.getPassword())) {
            loginLog.setLoginResult(LoginResultEnum.LOGIN_FAIL);
            loginLog.setException("密码错误");
            loginLog.setLoginIp(ip);
            sysUserLoginLogService.saveLog(loginLog);

            //用户错误次数超过5次，用户锁定
            user.setLoginErrorTimes(user.getLoginErrorTimes() == null ? 0 : user.getLoginErrorTimes() + 1);
            user.setLastLoginSuccTime(new Date());
            String erroMsg = "密码错误,剩余错误次数" + (5 - user.getLoginErrorTimes());;
            if (user.getLoginErrorTimes() >= 5) {
                user.setUserStatus(UserStatusEnum.LOCKED);
                erroMsg = "密码错误,用户已被锁定";
            }
            updateSelectiveById(user);
            log.info("用户名{}输入密码错误", username);
            throw new CodeException(ErrCodeEnum.ERR_CONSOLE, erroMsg);
        }
        roles = mapper.queryUserRole(user.getId());
        //TODO 抛出用户未拥有角色错误
        if (null == roles || roles.size() == 0) {
            log.info("用户名{}未拥有角色", username);
            throw new CodeException(ErrCodeEnum.ERR_CONSOLE, "用户无角色");
        }
        //查询用户所属项目id
        /*List<SysRoleProjectDto> projectDtos = sysRoleProjectDtoBiz.queryByRoleIds(roles);
        List<String> projectIds = new ArrayList<>();
        if (checkUserRole(resourceSuperAdmin,user.getId())){
            List<String> allProjectIds = getProjectIds();
            projectIds.addAll(allProjectIds);
        }else {
            if (checkUserRole(resourceServProAdmin,user.getId())){
                List<String> projectIdsByServiceProvider = getProjectIdsByServiceProvider(user.getServiceProvider());
                projectIds.addAll(projectIdsByServiceProvider);
            }
            if (null != projectDtos && projectDtos.size() > 0){
                for (SysRoleProjectDto dto : projectDtos){
                    if (StringUtils.isNotBlank(dto.getProjPkId())){
                        projectIds.add(dto.getProjPkId());
                    }
                }
            }
        }
        projectIds = projectIds.stream().distinct().collect(Collectors.toList());*/
        SysUserLoginVo vo = new SysUserLoginVo();
        BeanUtils.copyProperties(user, vo);
        vo.setRoles(roles);
        vo.setUserId(user.getId());
        /*vo.setProjectIds(projectIds);*/
        //修改最近登录时间
        user.setLastLoginSuccTime(new Date());
        //修改错误登录次数为0
        user.setLoginErrorTimes(0);
        updateSelectiveById(user);
        //新增登录日志
        loginLog.setLoginResult(LoginResultEnum.LOGIN_SUCCESS);
        loginLog.setLoginIp(ip);
        sysUserLoginLogService.saveLog(loginLog);
        return vo;
    }

    /**
     * 判断两个时间是否是同一天
     *
     * @param d1
     * @param d2
     * @return
     */
    private boolean isToday(Date d1, Date d2) {
        if (null == d1 || null == d2) {
            return false;
        }
        String pattern = "yyyy-MM-dd";
        if (DateUtil.format(d1, pattern).equals(DateUtil.format(d2, pattern))) {
            return true;
        }
        return false;
    }

    public SysUserDetailVo getPermissions(String userId) {
        SysUserDetailVo vo = new SysUserDetailVo();
        //查询用户信息
        SysUserDto userDto = new SysUserDto();
        userDto.setId(Long.valueOf(userId));
        userDto.setDeleteFlag(DeleteFlagEnum.NOT_DEL);
        userDto.setUserStatus(UserStatusEnum.NORMAL);
        userDto = selectOne(userDto);
        if (null == userDto) {
            return vo;
        }
        vo.setUserInfo(userDto);
        //查询用户的角色
        SysUserRoleDto userRoleDto = new SysUserRoleDto();
        userRoleDto.setUserId(Long.valueOf(userId));
        List<SysUserRoleDto> roleList = sysUserRoleDtoBiz.selectList(userRoleDto);
        List<Long> roles = new ArrayList<>();
        for (SysUserRoleDto dto : roleList) {
            roles.add(dto.getRoleId());
        }
        //查询用户的权限
        SysMenuVo menuVo = new SysMenuVo();
        menuVo.setRoleIds(roles);
        menuVo.setDeleteFlag(DeleteFlagEnum.NOT_DEL);
        List<SysMenuDto> userMenuAll = sysMenuDtoBiz.queryList(menuVo);

        List<SysMenuDto> menuList = new ArrayList<>();
        List<String> permissions = new ArrayList<>();
        for (SysMenuDto dto : userMenuAll) {
            if (MenuTypeEnum.MENU == dto.getMenuType()) {
                menuList.add(dto);
            } else {
                permissions.add(dto.getPermission());
            }
        }
        vo.setMenus(sysMenuDtoBiz.getMenu(menuList));
        vo.setPermissions(permissions);
        return vo;
    }

    /**
     * 用户唯一校验
     * @param sysUserVo
     * @return
     */
    public List<SysUserDto> uniqueUser(SysUserVo sysUserVo) {
        return mapper.uniqueUser(sysUserVo);
    }

    /**
     * 校验用户是否拥有某个角色
     * @param roleCode
     * @param userId
     * @return
     */
    public Boolean checkUserRole(String roleCode, Long userId) {
        if (null == userId || StringUtils.isBlank(roleCode)){
            return false;
        }
        SysUserRoleDto userRoleDto = new SysUserRoleDto();
        userRoleDto.setUserId(userId);
        List<SysUserRoleDto> roleList = sysUserRoleDtoBiz.selectList(userRoleDto);
        for (SysUserRoleDto dto : roleList) {
            SysRoleDto roleDto = new SysRoleDto();
            roleDto.setDeleteFlag(DeleteFlagEnum.NOT_DEL);
            roleDto.setId(dto.getRoleId());
            roleDto = sysRoleDtoBiz.selectOne(roleDto);
            //超级管理员可以看所有
            if (null != roleDto && roleCode.equals(roleDto.getRoleCode())){
                return true;
            }
        }
        return false;
    }

    /**
     * 获取所有项目ID集合
     * @return
     */
    public List<String> getProjectIds() {
        List<String> resultList = new ArrayList<>();

        String param = getJsonString();
        String responseStr = "";
        try {
            responseStr = HttpClientUtil.executPost(crmGetProject, param, "UTF-8", ContentType.APPLICATION_JSON);
        } catch (Exception e) {
            log.error("获取项目错误：{}",e.getMessage());
        }
        JSONObject json = (JSONObject) JSONObject.parse(responseStr);
        JSONObject plain = (JSONObject)json.get("plain");
        JSONObject detail = plain.getJSONObject("details");
        String resultCode = plain.getString("resultCode");

        if (resultCode.equals("000")){
            JSONArray items = detail.getJSONArray("items");
            if (null != items && items.size() > 0){
                for (int i = 0; i < items.size(); i++) {
                    JSONObject project = items.getJSONObject(i);
                    if (null == project) {
                        continue;
                    }
                    resultList.add(project.getString("id"));
                }
            }
        }
        return resultList;
    }

    /**
     * 根据服务商ID获取对应的项目ID集合
     * @param serviceProvider
     * @return
     */
    public List<String> getProjectIdsByServiceProvider(Long serviceProvider) {
        List<String> resultList = new ArrayList<>();

        String param = getJsonString(serviceProvider);
        String responseStr = "";
        try {
            responseStr = HttpClientUtil.executPost(crmGetProject, param, "UTF-8", ContentType.APPLICATION_JSON);
        } catch (Exception e) {
            log.error("服务商ID:{}，获取项目错误：{}",serviceProvider,e.getMessage());
        }
        JSONObject json = (JSONObject) JSONObject.parse(responseStr);
        JSONObject plain = (JSONObject)json.get("plain");
        JSONObject detail = plain.getJSONObject("details");
        String resultCode = plain.getString("resultCode");

        if (resultCode.equals("000")){
            JSONArray items = detail.getJSONArray("items");
            if (null != items && items.size() > 0){
                for (int i = 0; i < items.size(); i++) {
                    JSONObject project = items.getJSONObject(i);
                    if (null == project) {
                        continue;
                    }
                    resultList.add(project.getString("id"));
                }
            }
        }
        return resultList;
    }

    private String getJsonString(Long serviceProvider) {
        JSONObject json = new JSONObject();

        JSONObject plain = new JSONObject();
        plain.put("pageSize",0);
        plain.put("pageNum",0);

        JSONObject search = new JSONObject();
        search.put("spId",serviceProvider);

        plain.put("search",search);
        json.put("plain",plain);
        return json.toJSONString();
    }

    private String getJsonString() {
        JSONObject json = new JSONObject();

        JSONObject plain = new JSONObject();
        plain.put("pageSize",0);
        plain.put("pageNum",0);

        JSONObject search = new JSONObject();

        plain.put("search",search);
        json.put("plain",plain);
        return json.toJSONString();
    }


}
